﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.Net;
using System.Windows.Media.Animation;
using UMLObjects;


namespace WIN_UML_Editor
{
    /// <summary>
    /// Interaction logic for UCArrow.xaml
    /// </summary>
    public partial class UCArrow : UserControl, IUMLUC
    {
        private Point startOffSet = new Point(0,0);
        private Point endOffSet = new Point(0,0);

        //Colours of arrow
        private SolidColorBrush selectedColor = new SolidColorBrush(Colors.Maroon);
        private SolidColorBrush normalColor = new SolidColorBrush(Colors.Black);
        private SolidColorBrush arrowcolor;

        public string ObjName
        {
            get { return arrow.Name; }
            set { arrow.Name = value; }
        }

        public IUMLObject getObject()
        {
            return arrow;
        }

        private IArrowedUC pointingTo;
        public IArrowedUC PointingTo
        {
            get { return pointingTo; }
            set 
            { 
                pointingTo = value;
            }
        }

        private IArrowedUC pointingFrom;
        public IArrowedUC PointingFrom
        {
            get { return pointingFrom; }
            set { pointingFrom = value; }
        }

        private Arrow arrow;
        
        //Constructor with start values.
        public UCArrow(Arrow arrow, IArrowedUC to, IArrowedUC from)
        {
            InitializeComponent();  
            this.arrow = arrow;
            arrowcolor = normalColor;
            ArrowCanvas.DataContext = this.arrow;
            pointingTo = to;
            pointingFrom = from;
            Update();

            SolidColorBrush boxbg = new SolidColorBrush(Colors.White);
            boxbg.Opacity = 0.85;
            Namebox.Background = boxbg;
        }

        public void UpdateOffsets()
        {
            //Sizes
            Point fromSize = new Point(((FrameworkElement)pointingFrom).ActualWidth, ((FrameworkElement)pointingFrom).ActualHeight);
            Point toSize = new Point(((FrameworkElement)pointingTo).ActualWidth, ((FrameworkElement)pointingTo).ActualHeight);

            //Starting points
            Point from = new Point(Canvas.GetLeft((UIElement)pointingFrom)+fromSize.X*0.5,Canvas.GetTop((UIElement)pointingFrom)+fromSize.Y*0.5);
            Point to = new Point(Canvas.GetLeft((UIElement)pointingTo) + toSize.X*0.5, Canvas.GetTop((UIElement)pointingTo) + toSize.Y*0.5);
            Point vector = new Point(to.X-from.X,to.Y-from.Y);

            if (vector.X > Math.Abs(vector.Y)) //To the right
            {
                startOffSet.X = fromSize.X+3;
                startOffSet.Y = fromSize.Y * 0.5;
                endOffSet.X = 0 - 5;
                endOffSet.Y = toSize.Y * 0.5;
            }
            else if(vector.X < -Math.Abs(vector.Y)) //To the left
            {
                startOffSet.X = 0 - 3;
                startOffSet.Y = fromSize.Y * 0.5;
                endOffSet.X = toSize.X + 5;
                endOffSet.Y = toSize.Y * 0.5;
            }
            else if (vector.Y < -Math.Abs(vector.X)) //Above
            {
                startOffSet.X = fromSize.X * 0.5;
                startOffSet.Y = 0 - 3;
                endOffSet.X = toSize.X * 0.5;
                endOffSet.Y = toSize.Y + 5;

            }
            else if (vector.Y > -Math.Abs(vector.X)) //Below
            {
                startOffSet.X = fromSize.X * 0.5;
                startOffSet.Y = fromSize.Y + 3;
                endOffSet.X = toSize.X * 0.5;
                endOffSet.Y = 0 - 5;
            }
        }

        //Update position of arrow
        public void Update()
        {
            UpdateOffsets();
            //Read position of the element the arrow is pointing to
            UIElement elementfrom = pointingFrom as UIElement;
            UIElement elementto = pointingTo as UIElement;
            Point startPosition = new Point(Canvas.GetLeft(elementfrom), Canvas.GetTop(elementfrom));
            Point endPosition = new Point(Canvas.GetLeft(elementto), Canvas.GetTop(elementto));

            Point fromSize = new Point(((FrameworkElement)pointingFrom).ActualWidth, ((FrameworkElement)pointingFrom).ActualHeight);
            Point toSize = new Point(((FrameworkElement)pointingTo).ActualWidth, ((FrameworkElement)pointingTo).ActualHeight);
            Point from = new Point(Canvas.GetLeft((UIElement)pointingFrom) + fromSize.X * 0.5, Canvas.GetTop((UIElement)pointingFrom) + fromSize.Y * 0.5);
            Point to = new Point(Canvas.GetLeft((UIElement)pointingTo) + toSize.X * 0.5, Canvas.GetTop((UIElement)pointingTo) + toSize.Y * 0.5);
            Point vector = new Point(to.X - from.X, to.Y - from.Y);

            //Calculate angle
            double angleOfLine = Math.Atan2((endPosition.Y - startPosition.Y), (endPosition.X - startPosition.X)) * 180 / Math.PI;
            angleOfLine = Math.Round(angleOfLine / 90) * 90; //Round off to nearest 90 degrees

            //Add offset
            startPosition.X += startOffSet.X;
            startPosition.Y += startOffSet.Y;
            endPosition.X += endOffSet.X;
            endPosition.Y += endOffSet.Y;

            //reconfig all arrow points:
            
            //Arrow paths
            if (vector.X > Math.Abs(vector.Y) || vector.X < -Math.Abs(vector.Y)) //Til Venstre
            {
                // From start to breakpoint A
                StrokeSA.X1 = startPosition.X;
                StrokeSA.Y1 = startPosition.Y;
                StrokeSA.X2 = startPosition.X + ((endPosition.X - startPosition.X) / 2);
                StrokeSA.Y2 = startPosition.Y;
                StrokeSA.StrokeThickness = 2;
                StrokeSA.Stroke = arrowcolor;

                // From breakpoint A to breakpoint B
                StrokeAB.X1 = startPosition.X + ((endPosition.X - startPosition.X) / 2);
                StrokeAB.Y1 = startPosition.Y;
                StrokeAB.X2 = endPosition.X - ((endPosition.X - startPosition.X) / 2);
                StrokeAB.Y2 = endPosition.Y;
                StrokeAB.StrokeThickness = 2;
                StrokeAB.Stroke = arrowcolor;

                // From breakpoint B to end
                StrokeBE.X1 = endPosition.X - ((endPosition.X - startPosition.X) / 2);
                StrokeBE.Y1 = endPosition.Y;
                StrokeBE.X2 = endPosition.X;
                StrokeBE.Y2 = endPosition.Y;
                StrokeBE.StrokeThickness = 2;
                StrokeBE.Stroke = arrowcolor;
            }
            
            else if (vector.Y < -Math.Abs(vector.X) || vector.Y > -Math.Abs(vector.X)) //Under
            {
                // From start to breakpoint A
                StrokeSA.X1 = startPosition.X;
                StrokeSA.Y1 = startPosition.Y;
                StrokeSA.X2 = startPosition.X;
                StrokeSA.Y2 = startPosition.Y + ((endPosition.Y - startPosition.Y) / 2);
                StrokeSA.StrokeThickness = 2;
                StrokeSA.Stroke = arrowcolor;

                // From breakpoint A to breakpoint B
                StrokeAB.X1 = startPosition.X;
                StrokeAB.Y1 = startPosition.Y + ((endPosition.Y - startPosition.Y) / 2);
                StrokeAB.X2 = endPosition.X;
                StrokeAB.Y2 = endPosition.Y - ((endPosition.Y - startPosition.Y) / 2);
                StrokeAB.StrokeThickness = 2;
                StrokeAB.Stroke = arrowcolor;

                // From breakpoint B to end
                StrokeBE.X1 = endPosition.X;
                StrokeBE.Y1 = endPosition.Y - ((endPosition.Y - startPosition.Y) / 2);
                StrokeBE.X2 = endPosition.X;
                StrokeBE.Y2 = endPosition.Y;
                StrokeBE.StrokeThickness = 2;
                StrokeBE.Stroke = arrowcolor;
            }

            //Start symbol (filled circle)
            Start.Width = 7;
            Start.Height = 7;
            Start.Fill = arrowcolor;
            Canvas.SetLeft(Start, startPosition.X - (Start.Width / 2));
            Canvas.SetTop(Start, startPosition.Y - (Start.Height / 2));

            //End symbol (Filled triangle)
            End.X1 = endPosition.X;
            End.Y1 = endPosition.Y;
            End.X2 = endPosition.X;
            End.Y2 = endPosition.Y;
            End.StrokeEndLineCap = PenLineCap.Triangle;
            End.StrokeThickness = 10;
            End.Stroke = arrowcolor;

            EndRotateTransform.Angle = angleOfLine;
            EndRotateTransform.CenterX = endPosition.X;
            EndRotateTransform.CenterY = endPosition.Y;

            //Namebox for arrow
            if (Namebox.Text != "")
                Namebox.Padding = new Thickness(3);
            else
                Namebox.Padding = new Thickness(0);

            double nameY = startPosition.Y + (endPosition.Y - startPosition.Y) * 0.5 -Namebox.ActualHeight;
            double nameX = startPosition.X +(endPosition.X - startPosition.X) * 0.5 - Namebox.ActualWidth*0.5;
            Canvas.SetLeft(Namebox, nameX);
            Canvas.SetTop(Namebox, nameY+10);  
        }

        public void select()
        {
            arrowcolor = selectedColor;
            Update();
        }

        public void deselect()
        {
            arrowcolor = normalColor;
            Update();
        }
    }
}